// 加权因子数组
const WEIGHT_FACTORS: number[] = [
  7,
  9,
  10,
  5,
  8,
  4,
  2,
  1,
  6,
  3,
  7,
  9,
  10,
  5,
  8,
  4,
  2,
  1
];
  // 身份证验证位值，10代表X
const VALIDATION_CODES: (number | 'X')[] = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2];

/**
 * 验证身份证号码的有效性
 * @param idCard 身份证号码
 * @returns 是否有效
 */
export function validateIdCard(idCard: string): boolean {
  // 去除空格并修剪字符串
  idCard = trim(idCard.replace(/ /g, ''));

  // 根据身份证长度进行不同的验证
  if (idCard.length === 15) {
    return isValidBirthDateBy15IdCard(idCard);
  }
  else if (idCard.length === 18) {
    const idCardArray = idCard.split(''); // 将身份证号码分割成字符数组
    return (
      isValidBirthDateBy18IdCard(idCard)
      && isCorrectValidationCodeBy18IdCard(idCardArray)
    );
  }
  else {
    return false;
  }
}

/**
 * 判断18位身份证号码的最后一个验证位是否正确
 * @param idCardArray 身份证号码字符数组
 * @returns 是否正确
 */
function isCorrectValidationCodeBy18IdCard(idCardArray: string[]): boolean {
  let sum = 0; // 加权求和变量

  // 替换最后一位为10（即 'X'）以便后续处理
  if (idCardArray[17].toUpperCase() === 'X') {
    idCardArray[17] = '10';
  }

  // 加权求和
  for (let i = 0; i < 17; i++) {
    sum += WEIGHT_FACTORS[i] * Number(idCardArray[i]);
  }

  // 验证码位置
  const validationCodePosition = sum % 11;

  // 验证最后一位
  return Number(idCardArray[17]) === VALIDATION_CODES[validationCodePosition];
}

/**
 * 验证18位身份证号码中的生日是否有效
 * @param idCard18 18位身份证号码
 * @returns 是否有效
 */
function isValidBirthDateBy18IdCard(idCard18: string): boolean {
  const year = idCard18.substring(6, 10);
  const month = idCard18.substring(10, 12);
  const day = idCard18.substring(12, 14);

  const tempDate = new Date(Number(year), Number(month) - 1, Number(day));

  // 验证生日是否有效
  return !(
    tempDate.getFullYear() !== Number(year)
    || tempDate.getMonth() !== Number(month) - 1
    || tempDate.getDate() !== Number(day)
  );
}

/**
 * 验证15位身份证号码中的生日是否有效
 * @param idCard15 15位身份证号码
 * @returns 是否有效
 */
function isValidBirthDateBy15IdCard(idCard15: string): boolean {
  const year = `19${idCard15.substring(6, 8)}`;
  const month = idCard15.substring(8, 10);
  const day = idCard15.substring(10, 12);

  const tempDate = new Date(Number(year), Number(month) - 1, Number(day));

  // 验证生日是否有效
  return !(
    tempDate.getFullYear() !== Number(year)
    || tempDate.getMonth() !== Number(month) - 1
    || tempDate.getDate() !== Number(day)
  );
}

/**
 * 去掉字符串首尾空格
 * @param str 字符串
 * @returns 修剪后的字符串
 */
function trim(str: string): string {
  return str.replace(/(^\s*)|(\s*$)/g, '');
}
